package dst.ass1.jpa.interceptor;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;


public class ThreadSafeTest {
	static int methodN=0;
	static int n=0;
	static AtomicInteger atomicN=new AtomicInteger(0);
	private static final Object gate = new Object();
	static int gateN=0; 

	public static void main(String[] args) throws InterruptedException {
		//Difference between Logical and Physical Core
		//cmd -> wmic cpu get NumberOfCores,NumberOfLogicalProcessors 
		
		System.out.println("Run Thread Efficience Test - Available Processors to JAVA VM: "+ Runtime.getRuntime().availableProcessors());
		System.out.println("-------------------------------------------------------------");
		System.out.println("Value should be 200000000 otherwise the method is not threadsafe!!!!");
		System.out.println("-------------------------------------------------------------");
		runVersionNoSync();
		runVersionSyncMethod();
		runVersionGate();
		runVersionAtomicInt();
		System.out.println("-------------------------------------------------------------");
		System.out.println("AtomicInteger is much more performant than the gate or the method version!!!");
		System.out.println("-------------------------------------------------------------");
	}
	
	
	public static void runVersionNoSync() throws InterruptedException{
		Date start=new Date();
		
		Runnable r = new Runnable() {
	        public void run() {
	            for(int i = 0; i < 100000000; i++) {
	                n++;
	            }
	        }
	    };
	    
	    Thread t1 = new Thread(r);
	    Thread t2 = new Thread(r);
	    t1.start();
	    t2.start();
	    t1.join();
	    t2.join();
	    
	    Date end=new Date();
	    
	    System.out.println("NoSync -> Value: "+n+" Time: "+(end.getTime()-start.getTime())+"ms");
	}
	
	public static void runVersionSyncMethod() throws InterruptedException{
		Date start=new Date();
		
		Runnable r = new Runnable() {
	        public void run() {
	            for(int i = 0; i < 100000000; i++) {
	            	syncIncrement();
	            }
	        }
	    };
	    
	    Thread t1 = new Thread(r);
	    Thread t2 = new Thread(r);
	    t1.start();
	    t2.start();
	    t1.join();
	    t2.join();
	    
	    Date end=new Date();
	    
	    System.out.println("MethodSync -> Value: "+methodN+" Time: "+(end.getTime()-start.getTime())+"ms");
	}
	
	public synchronized static void syncIncrement(){
		methodN++;
	}
	
	public static void runVersionGate() throws InterruptedException{
		Date start=new Date();
		
		Runnable r = new Runnable() {
	        public void run() {
	            for(int i = 0; i < 100000000; i++) {
	                synchronized (gate) {
	                	gateN++;
	                }
	            }
	        }
	    };
	    
	    Thread t1 = new Thread(r);
	    Thread t2 = new Thread(r);
	    t1.start();
	    t2.start();
	    t1.join();
	    t2.join();
	    
	    Date end=new Date();
	    
	    System.out.println("GateSync -> Value: "+gateN+" Time: "+(end.getTime()-start.getTime())+"ms");
	}
	
	public static void runVersionAtomicInt() throws InterruptedException{
		Date start=new Date();
		
		Runnable r = new Runnable() {
	        public void run() {
	            for(int i = 0; i < 100000000; i++) {
	            	atomicN.getAndIncrement();
	            }
	        }
	    };
	    
	    Thread t1 = new Thread(r);
	    Thread t2 = new Thread(r);
	    t1.start();
	    t2.start();
	    t1.join();
	    t2.join();
	    
	    Date end=new Date();
	    
	    System.out.println("AtomicIntegerSync -> Value: "+atomicN.get()+" Time: "+(end.getTime()-start.getTime())+"ms");
	}
	
}
